import bpy
from typing import List
from ...addon.naming import FluidLabNaming
from .common_list_methods import FLUIDLAB_CommonList
from bpy.types import PropertyGroup, UIList, Object
from ...libs.functions.basics import set_active_object
from ...libs.functions.get_common_vars import get_common_vars
from bpy.props import StringProperty, IntProperty, CollectionProperty, BoolProperty, PointerProperty
from .basic_store_objects import StoredObjects
from datetime import datetime


""" Fluids Interactions List """


class FLUIDLAB_UL_draw_fluids_interactions(UIList):

    def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):
        
        if not item.id_name:
            layout.prop(item, "remove", text="Clear", icon='X')
            return

        left_sect = layout.row(align=True)

        # Item:
        left_sect.prop(item, "label_txt", text="", emboss=False)

        # Right Section:
        right_sect = left_sect.row(align=True)
        right_sect.alignment = 'RIGHT'

        # Remove icon:
        rm_button = right_sect.row(align=True)
        rm_button.alert = True
        rm_button.prop(item, "remove", text="", emboss=False, icon='X')


class FluidInteractionObjects(PropertyGroup):
    # main ob:
    ob: PointerProperty(type=Object)
    # resto de objetos:
    rest_obs: CollectionProperty(type=StoredObjects)


class FluidInteractionsListItem(PropertyGroup):
    label_txt: StringProperty(name="Name")
    id_name: StringProperty(name="ID")
        
    # Guardo los objectos principales:
    main_obs: CollectionProperty(type=FluidInteractionObjects)
    def add_interaction_main_ob(self, ob:Object) -> FluidInteractionObjects:
        main_ob_item = self.main_obs.add()
        main_ob_item.ob = ob
        return main_ob_item
    
    # Guardo el resto de objetos en el objeto principal:
    def add_interaction_rest_ob(self, main_ob_item:FluidInteractionObjects, ob: Object):
        rest_item = main_ob_item.rest_obs.add()
        rest_item.ob = ob
    
    def do_remove(self, context):
        start = datetime.now()

        fluid_interactions = get_common_vars(context, get_fluid_interactions=True)

        item = fluid_interactions.get_item_from_id(self.id_name)
        
        for main_ob_item in item.main_obs:
            
            # DEBUG:
            # print(f"\nmain_ob: {main_ob_item.ob.name}:")
            # for res_ob in main_ob_item.rest_obs:
            #     print(f"\tres_ob: {res_ob.ob.name}")

            main_ob = main_ob_item.ob
            set_active_object(context, main_ob)

            psys_active = main_ob.particle_systems.active
            if not psys_active:
                continue

            rest_obs = {ob_item.ob for ob_item in main_ob_item.rest_obs}

            if not rest_obs:
                continue

            # Primero eliminamos los targets válidos
            valid_targets = [target for target in psys_active.targets if target.object in rest_obs]
            for target in valid_targets:
                name = target.object.name + ": " + FluidLabNaming.PS_NAME
                idx = psys_active.targets.find(name)
                if idx != -1:
                    psys_active.active_particle_target_index = idx
                    with context.temp_override(particle_system=psys_active):
                        bpy.ops.particle.target_remove()

            # Luego eliminamos los 'Invalid target!'
            invalid_targets = [idx for idx, target in enumerate(psys_active.targets) if target.name == "Invalid target!"]
            for idx in invalid_targets:
                psys_active.active_particle_target_index = idx
                with context.temp_override(particle_system=psys_active):
                    bpy.ops.particle.target_remove()

        # Eliminamos el item del listado
        fluid_interactions.remove_item(self.id_name)
        print("[fluid interactions list remove] Time: " + str(datetime.now() - start))


    remove: BoolProperty(
        default=False, 
        update=do_remove
    )


class FluidInteractionsList(PropertyGroup, FLUIDLAB_CommonList):

    # Attributes (with or without methods):
    def list_index_update(self, context):
        item = self.active
        if not item:
            return
        pass
    
    list_index: IntProperty(name="Layer List", description="The Layer List", default=-1, update=list_index_update)
    list: CollectionProperty(type=FluidInteractionsListItem)

    # Fluid Interaction List Methods:
    def add_item(self, item_id:str, label_txt:str, interaction_obs:List[List[Object]]) -> None:

        item = self.list.add()
        item.id_name = item_id
        item.label_txt = label_txt

        # Guardo las relaciones del objeto -> y sus relaciones con el resto de los objetos:
        if len(interaction_obs) > 0:

            # Aplanando el listado 2D en 1D 
            # (y me aseguro de no tener duplicados):
            unique_obs = set()
            for row in interaction_obs:
                for ob in row:
                    unique_obs.add(ob)
            
            interaction_obs = list(unique_obs)
            for main_ob in interaction_obs:
                main_ob_item = item.add_interaction_main_ob(main_ob)
                
                # Guardo el resto de objetos:
                for rest_ob in interaction_obs:
                    if rest_ob == main_ob:
                        continue
                    item.add_interaction_rest_ob(main_ob_item, rest_ob)
    
        # seteamos el ultimo elemento como activo:
        self.list_index = self.length-1
    